{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# Flowers Image Classification with TensorFlow on Cloud ML Engine\n",
    "\n",
    "This notebook demonstrates how to do image classification from scratch on a flowers dataset using the Estimator API."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "import os\n",
    "PROJECT = \"cloud-training-demos\" # REPLACE WITH YOUR PROJECT ID\n",
    "BUCKET = \"cloud-training-demos-ml\" # REPLACE WITH YOUR BUCKET NAME\n",
    "REGION = \"us-central1\" # REPLACE WITH YOUR BUCKET REGION e.g. us-central1\n",
    "MODEL_TYPE = \"cnn\"\n",
    "\n",
    "# Do not change these\n",
    "os.environ[\"PROJECT\"] = PROJECT\n",
    "os.environ[\"BUCKET\"] = BUCKET\n",
    "os.environ[\"REGION\"] = REGION\n",
    "os.environ[\"MODEL_TYPE\"] = MODEL_TYPE\n",
    "os.environ[\"TFVERSION\"] = \"1.13\"  # Tensorflow version"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "%%bash\n",
    "gcloud config set project $PROJECT\n",
    "gcloud config set compute/region $REGION"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Input functions to read JPEG images\n",
    "\n",
    "The key difference between this notebook and [the MNIST one](./mnist_models.ipynb) is in the input function.\n",
    "In the input function here, we are doing the following:\n",
    "* Reading JPEG images, rather than 2D integer arrays.\n",
    "* Reading in batches of batch_size images rather than slicing our in-memory structure to be batch_size images.\n",
    "* Resizing the images to the expected HEIGHT, WIDTH. Because this is a real-world dataset, the images are of different sizes. We need to preprocess the data to, at the very least, resize them to constant size."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Run as a Python module\n",
    "\n",
    "Since we want to run our code on Cloud ML Engine, we've packaged it as a python module.\n",
    "\n",
    "The `model.py` and `task.py` containing the model code is in <a href=\"flowersmodel\">flowersmodel</a>\n",
    "\n",
    "**Complete the TODOs in `model.py` before proceeding!**\n",
    "\n",
    "Once you've completed the TODOs, run it locally for a few steps to test the code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "%%bash\n",
    "rm -rf flowersmodel.tar.gz flowers_trained\n",
    "gcloud ml-engine local train \\\n",
    "    --module-name=flowersmodel.task \\\n",
    "    --package-path=${PWD}/flowersmodel \\\n",
    "    -- \\\n",
    "    --output_dir=${PWD}/flowers_trained \\\n",
    "    --train_steps=5 \\\n",
    "    --learning_rate=0.01 \\\n",
    "    --batch_size=2 \\\n",
    "    --model=$MODEL_TYPE \\\n",
    "    --augment \\\n",
    "    --train_data_path=gs://cloud-ml-data/img/flower_photos/train_set.csv \\\n",
    "    --eval_data_path=gs://cloud-ml-data/img/flower_photos/eval_set.csv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "Now, let's do it on ML Engine. Note the --model parameter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "%%bash\n",
    "OUTDIR=gs://${BUCKET}/flowers/trained_${MODEL_TYPE}\n",
    "JOBNAME=flowers_${MODEL_TYPE}_$(date -u +%y%m%d_%H%M%S)\n",
    "echo $OUTDIR $REGION $JOBNAME\n",
    "gcloud storage rm --recursive --continue-on-error $OUTDIR\n",
    "gcloud ml-engine jobs submit training $JOBNAME \\\n",
    "    --region=$REGION \\\n",
    "    --module-name=flowersmodel.task \\\n",
    "    --package-path=${PWD}/flowersmodel \\\n",
    "    --job-dir=$OUTDIR \\\n",
    "    --staging-bucket=gs://$BUCKET \\\n",
    "    --scale-tier=BASIC_GPU \\\n",
    "    --runtime-version=$TFVERSION \\\n",
    "    -- \\\n",
    "    --output_dir=$OUTDIR \\\n",
    "    --train_steps=1000 \\\n",
    "    --learning_rate=0.01 \\\n",
    "    --batch_size=40 \\\n",
    "    --model=$MODEL_TYPE \\\n",
    "    --augment \\\n",
    "    --batch_norm \\\n",
    "    --train_data_path=gs://cloud-ml-data/img/flower_photos/train_set.csv \\\n",
    "    --eval_data_path=gs://cloud-ml-data/img/flower_photos/eval_set.csv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Monitoring training with TensorBoard\n",
    "\n",
    "Use this cell to launch tensorboard"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "from google.datalab.ml import TensorBoard\n",
    "TensorBoard().start(\"gs://{}/flowers/trained_{}\".format(BUCKET, MODEL_TYPE))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "for pid in TensorBoard.list()[\"pid\"]:\n",
    "    TensorBoard().stop(pid)\n",
    "    print(\"Stopped TensorBoard with pid {}\".format(pid))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "Here are my results:\n",
    "\n",
    "Model | Accuracy | Time taken | Run time parameters\n",
    "--- | :---: | ---\n",
    "cnn with batch-norm | 0.582 | 47 min | 1000 steps, LR=0.01, Batch=40\n",
    "as above, plus augment | 0.615 | 3 hr | 5000 steps, LR=0.01, Batch=40\n",
    "\n",
    "What was your accuracy?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Deploying and predicting with model\n",
    "\n",
    "Deploy the model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "%%bash\n",
    "MODEL_NAME=\"flowers\"\n",
    "MODEL_VERSION=${MODEL_TYPE}\n",
    "MODEL_LOCATION=$(gcloud storage ls gs://${BUCKET}/flowers/trained_${MODEL_TYPE}/export/exporter | tail -1)\n",
    "echo \"Deleting and deploying $MODEL_NAME $MODEL_VERSION from $MODEL_LOCATION ... this will take a few minutes\"\n",
    "#gcloud ml-engine versions delete --quiet ${MODEL_VERSION} --model ${MODEL_NAME}\n",
    "#gcloud ml-engine models delete ${MODEL_NAME}\n",
    "gcloud ml-engine models create ${MODEL_NAME} --regions $REGION\n",
    "gcloud ml-engine versions create ${MODEL_VERSION} --model ${MODEL_NAME} --origin ${MODEL_LOCATION} --runtime-version=$TFVERSION"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "To predict with the model, let's take one of the example images that is available on Google Cloud Storage <img src=\"http://storage.googleapis.com/cloud-ml-data/img/flower_photos/sunflowers/1022552002_2b93faf9e7_n.jpg\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The online prediction service expects images to be base64 encoded as described [here](https://cloud.google.com/ml-engine/docs/tensorflow/online-predict#binary_data_in_prediction_input)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "%%bash\n",
    "IMAGE_URL=gs://cloud-ml-data/img/flower_photos/sunflowers/1022552002_2b93faf9e7_n.jpg\n",
    "\n",
    "# Copy the image to local disk.\n",
    "gcloud storage cp $IMAGE_URL flower.jpg\n",
    "\n",
    "# Base64 encode and create request message in json format.\n",
    "python -c 'import base64, sys, json; img = base64.b64encode(open(\"flower.jpg\", \"rb\").read()).decode(); print(json.dumps({\"image_bytes\":{\"b64\": img}}))' &> request.json"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "Send it to the prediction service"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "%%bash\n",
    "gcloud ml-engine predict \\\n",
    "  --model=flowers \\\n",
    "  --version=${MODEL_TYPE} \\\n",
    "  --json-instances=./request.json"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "<pre>\n",
    "# Copyright 2017 Google Inc. All Rights Reserved.\n",
    "#\n",
    "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
    "# you may not use this file except in compliance with the License.\n",
    "# You may obtain a copy of the License at\n",
    "#\n",
    "#      http://www.apache.org/licenses/LICENSE-2.0\n",
    "#\n",
    "# Unless required by applicable law or agreed to in writing, software\n",
    "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
    "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
    "# See the License for the specific language governing permissions and\n",
    "# limitations under the License.\n",
    "</pre>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
